package com.uziot.bucket.tasklock.aspect;

import com.uziot.bucket.tasklock.dao.TaskLock;
import com.uziot.bucket.tasklock.dao.TaskLog;
import com.uziot.bucket.tasklock.service.TaskLockService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 功能描述: <br>
 * 定时任务锁切面执行类，动态执行不需要手动创建对象
 *
 * @author shidt
 * @date 2020-03-09 0:00
 */
@Slf4j
@Aspect
@Component
public class TaskDbLockAspect {

    @Autowired
    private TaskLockService taskLockService;

    @Around("@annotation(taskDbLock)")
    public Object around(ProceedingJoinPoint joinPoint, TaskDbLock taskDbLock) throws Throwable {

        // 方法内的所有参数
        Object[] params = joinPoint.getArgs();
        // 获取锁索引列表
        int[] lockIndexs = taskDbLock.lockIndexs();
        // 获取字段列表
        String[] fieldNames = taskDbLock.fieldNames();
        // 获得锁，锁默认使用的是锁方法
        String lockName;
        if (lockIndexs.length == 0) {
            lockName = joinPoint.getSignature().getName();
        } else {
            // 锁方法 + 字段值
            lockName = joinPoint.getSignature().getName() + "." +
                    ReflectionUtils.getPropertyParams(params, lockIndexs, fieldNames);
        }
        TaskLock taskLock = taskLockService.createTaskLock(lockName);
        boolean lock = taskLockService.tryLock(taskLock);
        TaskLog taskLog = taskLockService.createTaskLog(lockName);
        Object result = null;
        try {
            // 获得成功
            if (lock) {
                taskLockService.saveTaskLog(taskLog);
                result = joinPoint.proceed();
                //记录定时任务日志表
                taskLog.setResult("normal");
            }
            // 当获取锁失败时,抛出异常消息
            if (taskDbLock.throwError()) {
                throw new Exception(taskDbLock.msg());
            }
        } catch (Throwable e) {
            taskLog.setResult("error");
            throw new Throwable(e);
        } finally {
            //修改定时任务日志表
            taskLockService.updateTaskLog(taskLog);
            //释放全局锁
            taskLockService.removeTaskLock(taskLock);
        }
        return result;
    }
}